import json

from re_common.baselibrary.utils.core.mdeprecated import try_except2_async

from apps.crawler_platform.core_abs.downstepabs import BaseCoreABS
from apps.crawler_platform.core_callback.err_callback import all_client_back_callback


class CoreLocalEtlControllerMixin(BaseCoreABS):
    """
      本地etl核心控制器,查询mysql拿出task信息,去mongo拿到对应的文章下载内容解析,解析结果存入mongo里的journal_latest,打标
    """

    async def _base_task_step(self):
        """
        :return:
        """
        self.step_info = self.add_all_process_info(f"etl获取redis的配置信息，配置信息来源于sql表taskinfo 3")
        # 获取redis配置信息
        bools, err_info = await self.get_redis()
        if not bools:
            self.add_process_info(self.step_info + " 该步骤错误")
            return bools, err_info

        self.step_info = self.add_all_process_info(f"etl解析获取sql的单条数据 1")
        bools, err_info = await self.get_sql()
        if not bools:
            self.add_process_info(self.step_info + " 该步骤错误")
            return bools, err_info

        # 对于一个网页可能有多个部分内容组成，循环设置
        for keys in sorted(self.get_redis_model().parse_dict.keys()):
            # 设置pm的keys
            self.pm.keys = keys

            self.step_info = self.add_all_process_info(f"etl开始解析redis结构2,key is {keys};")
            bools, err_info = self.para_redis(keys)
            if not bools:
                self.add_process_info(self.step_info + " 该步骤错误")
                return bools, err_info

            self.pm.redis_model.parse_dict[keys].task_info.parse_rules = self.pm.redis_model.parse_dict[
                keys].task_info.etl_rules

        self.step_info = self.add_all_process_info(f"etl开始读取no_sql,并且处理html")
        # # # 设置对应的model来接收下载的结果
        # self.pm.set_downmodel()
        # 保存和查询mongo的必要参数
        self.pm.set_para()
        bools, err_info = await self.read_nosql_html()
        if not bools:
            self.add_process_info(self.step_info + " 该步骤错误")
            return bools, err_info

        self.step_info = self.add_all_process_info(f"开始解析html")
        bools, err_info = await self.deal_html_etl()
        if not bools:
            self.add_process_info(self.step_info)
            return bools, err_info

        self.step_info = self.add_all_process_info(f"解析完成,验证解析出来的数据是否正确")
        bools, err_info = self.verify_para()
        if not bools:
            self.add_process_info(self.step_info)
            return bools, err_info

        self.step_info = self.add_all_process_info(f"etl解析完成，开始将解析结果保存nosql;")
        bools, err_info = await self.save_nosql_html_etl()
        if not bools:
            self.add_process_info(self.step_info)
            return bools, err_info

        return True, {}

    @try_except2_async(callback=all_client_back_callback, is_print=True)
    async def _easy_task_step(self):
        """
        :return:
        """
        bools, err_info = await self._base_task_step()
        # 需要上个步骤的结果在sql中做出判断
        bools_sql, err_info_sql = await self.save_sql(code=bools, err_msg=err_info)

        if not bools_sql:
            return bools_sql, err_info_sql
        return bools, err_info

    @try_except2_async(callback=all_client_back_callback, is_print=True)
    async def task_step(self):
        """
        最终调度
        """
        return await self._easy_task_step()


class CoreRemoteEtlControllerMixin(BaseCoreABS):
    """
        远程etl核心控制器,查询mysql拿出task信息,去mongo的journal_latest拿到对应的文章解析好的内容，发送远程etl接口,并打标相应状态
    """

    async def _base_task_step(self):
        """
        :return:
        """
        # 限制只允许指定函数调用 由于这里面没有save_sal 由easy_task_step保证save_sal的执行
        # if inspect.stack()[1].function != "_easy_task_step":
        #     raise Exception("不允许easy_task_step以外的函数调用_base_task_step")
        # self.step_info = self.add_all_process_info(f"获取redis的配置信息，配置信息来源于sql表taskinfo 4")
        # # 获取redis配置信息
        bools, err_info = await self.get_redis()
        if not bools:
            return bools, err_info
        self.step_info = self.add_all_process_info(f"发送获取sql的单条数据")
        bools, err_info = await self.get_sql()
        if not bools:
            return bools, err_info
        self.step_info = self.add_all_process_info(f"开始读取no_sql,处理html")
        # bools, err_info = await self.read_nosql_latest()
        # if not bools:
        #     return bools, err_info
        # data = self.pm.mongo_html["data"]
        # 如果mongo查出来不存在
        # if not data:
        #     return False, "latest表未查询到数据"
        self.step_info = self.add_all_process_info(f"将latest表记录发送至平台ETL接口")
        bools, dicts = await self.do_etl_remote()
        if not bools:
            return bools, dicts
        self.step_info = self.add_all_process_info(f"etl结果发送远程处理接口完成,打标is_true=8")
        rshtml = self.pm.resp_html
        rsjson = json.loads(rshtml)
        bools, err_info = await self.save_sql(code="8", err_info=rsjson.get("data", ""))
        if not bools:
            return bools, err_info
        # 返回一个整体的状态
        return bools, ""

    @try_except2_async(callback=all_client_back_callback, is_print=True)
    async def _easy_task_step(self):
        """
        :return:
        """
        bools, err_info = await self._base_task_step()
        if bools:
            self.step_info = self.add_all_process_info(f"解析完成，更新sql;")
        # 下载中途失败退出也需要更新状态码，如果存在的话
        if not bools:
            err_msg = json.dumps(err_info, ensure_ascii=False)
            bools2, err_info2 = await self.save_sql(code="7", err_info=err_msg)
            if bools2:
                self.step_info = self.add_all_process_info(f"etl解析完成，更新状态码;")
        if bools:
            self.step_info = self.add_all_process_info(f"etl解析完成，所有逻辑成功;")
        return bools, err_info

    @try_except2_async(callback=all_client_back_callback, is_print=True)
    async def task_step(self):
        """
        最终调度
        """
        return await self._easy_task_step()
